//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package roadmap_content_api_serv

import (
	"context"

	"atomgit.com/openlinksaas-org/api-server/admin_api_serv/admin_common"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/roadmap_dao"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/admin_auth_api"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/roadmap_api"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/roadmap_content_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *RoadmapContentApiImpl) AddNode(ctx context.Context, req *roadmap_content_api.AddNodeRequest) (*roadmap_content_api.AddNodeResponse, error) {
	ownerType := roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_ADMIN
	ownerUserId := ""
	var roadmapPerm *admin_auth_api.RoadmapPerm
	isWhiteUser := false

	userSess, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if ok {
		ownerType = roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_USER
		ownerUserId = userSess.UserId
		exist, err := roadmap_dao.WhiteUserDao.Exist(ctx, userSess.UserId)
		if err != nil {
			return nil, err
		}
		isWhiteUser = exist
	} else {
		adminSess, ok := dao.CacheDao.GetAdminSession(ctx, req.SessionId)
		if !ok {
			return &roadmap_content_api.AddNodeResponse{
				Code:   roadmap_content_api.AddNodeResponse_CODE_WRONG_SESSION,
				ErrMsg: "会话不存在",
			}, nil
		}
		if !adminSess.AuthOk {
			return &roadmap_content_api.AddNodeResponse{
				Code:   roadmap_content_api.AddNodeResponse_CODE_NOT_AUTH,
				ErrMsg: "未授权会话",
			}, nil
		}
		adminUserCfg, err := admin_common.GetAdminUserConfig(ctx, apiImpl.adminCfg, adminSess.UserName)
		if err != nil {
			return nil, err
		}
		if !adminUserCfg.PermInfo.RoadmapPerm.Read {
			return &roadmap_content_api.AddNodeResponse{
				Code:   roadmap_content_api.AddNodeResponse_CODE_NO_PERMISSION,
				ErrMsg: "没有权限",
			}, nil
		}
		ownerType = roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_ADMIN
		ownerUserId = adminSess.UserName
		roadmapPerm = adminUserCfg.PermInfo.RoadmapPerm
	}

	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &roadmap_content_api.AddNodeResponse{
			Code:   roadmap_content_api.AddNodeResponse_CODE_NO_ROADMAP,
			ErrMsg: "路线图不存在",
		}, nil
	}
	userPerm := apiImpl.calcUserPerm(roadmapItem, ownerType, ownerUserId, roadmapPerm, isWhiteUser)
	if !userPerm.CanUpdateContent {
		return &roadmap_content_api.AddNodeResponse{
			Code:   roadmap_content_api.AddNodeResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	nodeId := uuid.NewString()

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		dbItem := &roadmap_dao.NodeInfoDbItem{
			NodeId: nodeId,
			BasicInfo: roadmap_dao.BasicNodeInfoDbItem{
				NodeType: uint32(req.BasicInfo.NodeType),
				W:        req.BasicInfo.NodeSize.W,
				H:        req.BasicInfo.NodeSize.H,
				X:        req.BasicInfo.NodePosition.X,
				Y:        req.BasicInfo.NodePosition.Y,
			},
			RoadmapId: req.RoadmapId,
		}
		if req.BasicInfo.NodeType == roadmap_content_api.NODE_TYPE_NODE_LABEL {
			nodeData, ok := req.BasicInfo.NodeData.(*roadmap_content_api.BasicNodeInfo_TextData)
			if !ok {
				nodeData = &roadmap_content_api.BasicNodeInfo_TextData{
					TextData: &roadmap_content_api.NodeDataText{
						FontSize:   14,
						FontWeight: 500,
						FontColor:  "black",
						Content:    "",
						BgColor:    "white",
					},
				}
			}
			dbItem.BasicInfo.TextData = &roadmap_dao.NodeDataTextDbItem{
				FontSize:   nodeData.TextData.FontSize,
				FontWeight: nodeData.TextData.FontWeight,
				FontColor:  nodeData.TextData.FontColor,
				Content:    nodeData.TextData.Content,
				BgColor:    nodeData.TextData.BgColor,
			}
		} else if req.BasicInfo.NodeType == roadmap_content_api.NODE_TYPE_NODE_RICH_TEXT {
			nodeData, ok := req.BasicInfo.NodeData.(*roadmap_content_api.BasicNodeInfo_RichTextData)
			if !ok {
				nodeData = &roadmap_content_api.BasicNodeInfo_RichTextData{
					RichTextData: &roadmap_content_api.NodeDataRichText{
						Content: "",
						BgColor: "white",
					},
				}
			}
			dbItem.BasicInfo.RichTextData = &roadmap_dao.NodeDataRichTextDbItem{
				Content: nodeData.RichTextData.Content,
				BgColor: nodeData.RichTextData.BgColor,
			}
		} else if req.BasicInfo.NodeType == roadmap_content_api.NODE_TYPE_NODE_TOPIC || req.BasicInfo.NodeType == roadmap_content_api.NODE_TYPE_NODE_SUB_TOPIC {
			nodeData, ok := req.BasicInfo.NodeData.(*roadmap_content_api.BasicNodeInfo_TopicData)
			if !ok {
				nodeData = &roadmap_content_api.BasicNodeInfo_TopicData{
					TopicData: &roadmap_content_api.NodeDataTopic{
						FontSize:    14,
						FontWeight:  500,
						FontColor:   "black",
						Title:       "",
						BgColor:     "white",
						Content:     "",
						LearnPolicy: roadmap_content_api.LEARN_POLICY_TYPE_LEARN_POLICY_NONE,
						LinkList:    []*roadmap_content_api.ExtraLinkItem{},
					},
				}
			}
			linkList := []roadmap_dao.ExtraLinkItemDbItem{}
			if nodeData.TopicData.LinkList != nil {
				for _, linkItem := range nodeData.TopicData.LinkList {
					linkList = append(linkList, roadmap_dao.ExtraLinkItemDbItem{
						LinkId:    linkItem.LinkId,
						LinkType:  uint32(linkItem.LinkType),
						LinkTitle: linkItem.LinkTitle,
						LinkUrl:   linkItem.LinkUrl,
					})
				}
			}
			dbItem.BasicInfo.TopicData = &roadmap_dao.NodeDataTopicDbItem{
				FontSize:    nodeData.TopicData.FontSize,
				FontWeight:  nodeData.TopicData.FontWeight,
				FontColor:   nodeData.TopicData.FontColor,
				Title:       nodeData.TopicData.Title,
				BgColor:     nodeData.TopicData.BgColor,
				Content:     nodeData.TopicData.Content,
				LearnPolicy: uint32(nodeData.TopicData.LearnPolicy),
				LinkList:    linkList,
			}
		} else if req.BasicInfo.NodeType == roadmap_content_api.NODE_TYPE_NODE_TODO_LIST {
			nodeData, ok := req.BasicInfo.NodeData.(*roadmap_content_api.BasicNodeInfo_TodoListData)
			if !ok {
				nodeData = &roadmap_content_api.BasicNodeInfo_TodoListData{
					TodoListData: &roadmap_content_api.NodeDataTodoList{
						ItemList: []*roadmap_content_api.NodeTodoItem{},
						BgColor:  "white",
					},
				}
			}
			itemList := []roadmap_dao.NodeTodoItemDbItem{}
			for _, srcItem := range nodeData.TodoListData.ItemList {
				itemList = append(itemList, roadmap_dao.NodeTodoItemDbItem{
					TodoId: srcItem.TodoId,
					Title:  srcItem.Title,
				})
			}
			dbItem.BasicInfo.TodoListData = &roadmap_dao.NodeDataTodoListDbItem{
				ItemList: itemList,
				BgColor:  nodeData.TodoListData.BgColor,
			}
		} else if req.BasicInfo.NodeType == roadmap_content_api.NODE_TYPE_NODE_GROUP {
			nodeData, ok := req.BasicInfo.NodeData.(*roadmap_content_api.BasicNodeInfo_GroupData)
			if !ok {
				nodeData = &roadmap_content_api.BasicNodeInfo_GroupData{
					GroupData: &roadmap_content_api.NodeDataGroup{
						BgColor:      "white",
						BorderColor:  "black",
						BorderRadius: 0,
					},
				}
			}
			dbItem.BasicInfo.GroupData = &roadmap_dao.NodeDataGroupDbItem{
				BgColor:      nodeData.GroupData.BgColor,
				BorderColor:  nodeData.GroupData.BorderColor,
				BorderRadius: nodeData.GroupData.BorderRadius,
			}
		} else if req.BasicInfo.NodeType == roadmap_content_api.NODE_TYPE_NODE_ROADMAP_REF {
			nodeData, ok := req.BasicInfo.NodeData.(*roadmap_content_api.BasicNodeInfo_RoadmapRefData)
			if !ok {
				nodeData = &roadmap_content_api.BasicNodeInfo_RoadmapRefData{
					RoadmapRefData: &roadmap_content_api.NodeDataRoadmapRef{},
				}
			}
			dbItem.BasicInfo.RoadmapRefData = &roadmap_dao.NodeDataRoadmapRefDbItem{
				TargetTitle: nodeData.RoadmapRefData.TargetTitle,
				TargetId:    nodeData.RoadmapRefData.TargetId,
			}
		} else if req.BasicInfo.NodeType == roadmap_content_api.NODE_TYPE_NODE_WEB_LINK {
			nodeData, ok := req.BasicInfo.NodeData.(*roadmap_content_api.BasicNodeInfo_WebLinkData)
			if !ok {
				nodeData = &roadmap_content_api.BasicNodeInfo_WebLinkData{
					WebLinkData: &roadmap_content_api.NodeDataWebLink{},
				}
			}
			dbItem.BasicInfo.WebLinkData = &roadmap_dao.NodeDataWebLinkDbItem{
				LinkName: nodeData.WebLinkData.LinkName,
				LinkUrl:  nodeData.WebLinkData.LinkUrl,
			}
		} else if req.BasicInfo.NodeType == roadmap_content_api.NODE_TYPE_NODE_CODE {
			nodeData, ok := req.BasicInfo.NodeData.(*roadmap_content_api.BasicNodeInfo_CodeData)
			if !ok {
				nodeData = &roadmap_content_api.BasicNodeInfo_CodeData{
					CodeData: &roadmap_content_api.NodeDataCode{},
				}
			}
			dbItem.BasicInfo.CodeData = &roadmap_dao.NodeDataCodeDbItem{
				Lang: nodeData.CodeData.Lang,
				Code: nodeData.CodeData.Code,
			}
		}
		err = roadmap_dao.NodeDao.Insert(sessCtx, dbItem)
		if err != nil {
			return nil, err
		}
		return &roadmap_content_api.AddNodeResponse{
			Code:   roadmap_content_api.AddNodeResponse_CODE_OK,
			NodeId: nodeId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*roadmap_content_api.AddNodeResponse), nil
}

func (apiImpl *RoadmapContentApiImpl) ListNode(ctx context.Context, req *roadmap_content_api.ListNodeRequest) (*roadmap_content_api.ListNodeResponse, error) {
	emptyList := []*roadmap_content_api.NodeInfo{}

	ownerType := roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_ADMIN
	ownerUserId := ""

	userSess, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if ok {
		ownerType = roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_USER
		ownerUserId = userSess.UserId
	} else {
		adminSess, ok := dao.CacheDao.GetAdminSession(ctx, req.SessionId)
		if !ok {
			return &roadmap_content_api.ListNodeResponse{
				Code:     roadmap_content_api.ListNodeResponse_CODE_WRONG_SESSION,
				ErrMsg:   "会话不存在",
				NodeList: emptyList,
			}, nil
		}
		if !adminSess.AuthOk {
			return &roadmap_content_api.ListNodeResponse{
				Code:     roadmap_content_api.ListNodeResponse_CODE_NOT_AUTH,
				ErrMsg:   "未授权会话",
				NodeList: emptyList,
			}, nil
		}
		adminUserCfg, err := admin_common.GetAdminUserConfig(ctx, apiImpl.adminCfg, adminSess.UserName)
		if err != nil {
			return nil, err
		}
		if !adminUserCfg.PermInfo.RoadmapPerm.Read {
			return &roadmap_content_api.ListNodeResponse{
				Code:     roadmap_content_api.ListNodeResponse_CODE_NO_PERMISSION,
				ErrMsg:   "没有权限",
				NodeList: emptyList,
			}, nil
		}
		ownerType = roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_ADMIN
		ownerUserId = adminSess.UserName
	}

	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &roadmap_content_api.ListNodeResponse{
			Code:     roadmap_content_api.ListNodeResponse_CODE_NO_ROADMAP,
			ErrMsg:   "路线图不存在",
			NodeList: emptyList,
		}, nil
	}
	if ownerType == roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_USER {
		//只能访问自己和公开的
		if !(roadmapItem.OwnerUserId == ownerUserId || roadmapItem.PubState) {
			return &roadmap_content_api.ListNodeResponse{
				Code:     roadmap_content_api.ListNodeResponse_CODE_NO_PERMISSION,
				ErrMsg:   "没有权限",
				NodeList: emptyList,
			}, nil
		}
	}

	nodeItemList, err := roadmap_dao.NodeDao.List(ctx, req.RoadmapId)
	if err != nil {
		return nil, err
	}
	nodeList := []*roadmap_content_api.NodeInfo{}
	for _, nodeItem := range nodeItemList {
		nodeList = append(nodeList, nodeItem.ToNodeInfo())
	}
	return &roadmap_content_api.ListNodeResponse{
		Code:     roadmap_content_api.ListNodeResponse_CODE_OK,
		NodeList: nodeList,
	}, nil
}

func (apiImpl *RoadmapContentApiImpl) GetNode(ctx context.Context, req *roadmap_content_api.GetNodeRequest) (*roadmap_content_api.GetNodeResponse, error) {
	emptyInfo := &roadmap_content_api.NodeInfo{
		BasicInfo: &roadmap_content_api.BasicNodeInfo{
			NodeSize:     &roadmap_content_api.NodeSize{},
			NodePosition: &roadmap_content_api.NodePosition{},
			NodeData: &roadmap_content_api.BasicNodeInfo_TextData{
				TextData: &roadmap_content_api.NodeDataText{},
			},
		},
	}

	ownerType := roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_ADMIN
	ownerUserId := ""

	userSess, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if ok {
		ownerType = roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_USER
		ownerUserId = userSess.UserId
	} else {
		adminSess, ok := dao.CacheDao.GetAdminSession(ctx, req.SessionId)
		if !ok {
			return &roadmap_content_api.GetNodeResponse{
				Code:   roadmap_content_api.GetNodeResponse_CODE_WRONG_SESSION,
				ErrMsg: "会话不存在",
				Node:   emptyInfo,
			}, nil
		}
		if !adminSess.AuthOk {
			return &roadmap_content_api.GetNodeResponse{
				Code:   roadmap_content_api.GetNodeResponse_CODE_NOT_AUTH,
				ErrMsg: "未授权会话",
				Node:   emptyInfo,
			}, nil
		}
		adminUserCfg, err := admin_common.GetAdminUserConfig(ctx, apiImpl.adminCfg, adminSess.UserName)
		if err != nil {
			return nil, err
		}
		if !adminUserCfg.PermInfo.RoadmapPerm.Read {
			return &roadmap_content_api.GetNodeResponse{
				Code:   roadmap_content_api.GetNodeResponse_CODE_NO_PERMISSION,
				ErrMsg: "没有权限",
				Node:   emptyInfo,
			}, nil
		}
		ownerType = roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_ADMIN
		ownerUserId = adminSess.UserName
	}

	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &roadmap_content_api.GetNodeResponse{
			Code:   roadmap_content_api.GetNodeResponse_CODE_NO_ROADMAP,
			ErrMsg: "路线图不存在",
			Node:   emptyInfo,
		}, nil
	}
	if ownerType == roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_USER {
		//只能访问自己和公开的
		if !(roadmapItem.OwnerUserId == ownerUserId || roadmapItem.PubState) {
			return &roadmap_content_api.GetNodeResponse{
				Code:   roadmap_content_api.GetNodeResponse_CODE_NO_PERMISSION,
				ErrMsg: "没有权限",
				Node:   emptyInfo,
			}, nil
		}
	}
	nodeItem, err := roadmap_dao.NodeDao.Get(ctx, req.RoadmapId, req.NodeId)
	if err != nil {
		return &roadmap_content_api.GetNodeResponse{
			Code:   roadmap_content_api.GetNodeResponse_CODE_NO_NODE,
			ErrMsg: "节点不存在",
			Node:   emptyInfo,
		}, nil
	}
	return &roadmap_content_api.GetNodeResponse{
		Code: roadmap_content_api.GetNodeResponse_CODE_OK,
		Node: nodeItem.ToNodeInfo(),
	}, nil
}

func (apiImpl *RoadmapContentApiImpl) UpdateNodeSize(ctx context.Context, req *roadmap_content_api.UpdateNodeSizeRequest) (*roadmap_content_api.UpdateNodeSizeResponse, error) {
	ownerType := roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_ADMIN
	ownerUserId := ""
	var roadmapPerm *admin_auth_api.RoadmapPerm
	isWhiteUser := false

	userSess, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if ok {
		ownerType = roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_USER
		ownerUserId = userSess.UserId
		exist, err := roadmap_dao.WhiteUserDao.Exist(ctx, userSess.UserId)
		if err != nil {
			return nil, err
		}
		isWhiteUser = exist
	} else {
		adminSess, ok := dao.CacheDao.GetAdminSession(ctx, req.SessionId)
		if !ok {
			return &roadmap_content_api.UpdateNodeSizeResponse{
				Code:   roadmap_content_api.UpdateNodeSizeResponse_CODE_WRONG_SESSION,
				ErrMsg: "会话不存在",
			}, nil
		}
		if !adminSess.AuthOk {
			return &roadmap_content_api.UpdateNodeSizeResponse{
				Code:   roadmap_content_api.UpdateNodeSizeResponse_CODE_NOT_AUTH,
				ErrMsg: "未授权会话",
			}, nil
		}
		adminUserCfg, err := admin_common.GetAdminUserConfig(ctx, apiImpl.adminCfg, adminSess.UserName)
		if err != nil {
			return nil, err
		}
		if !adminUserCfg.PermInfo.RoadmapPerm.Read {
			return &roadmap_content_api.UpdateNodeSizeResponse{
				Code:   roadmap_content_api.UpdateNodeSizeResponse_CODE_NO_PERMISSION,
				ErrMsg: "没有权限",
			}, nil
		}
		ownerType = roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_ADMIN
		ownerUserId = adminSess.UserName
		roadmapPerm = adminUserCfg.PermInfo.RoadmapPerm
	}

	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &roadmap_content_api.UpdateNodeSizeResponse{
			Code:   roadmap_content_api.UpdateNodeSizeResponse_CODE_NO_ROADMAP,
			ErrMsg: "路线图不存在",
		}, nil
	}
	userPerm := apiImpl.calcUserPerm(roadmapItem, ownerType, ownerUserId, roadmapPerm, isWhiteUser)
	if !userPerm.CanUpdateContent {
		return &roadmap_content_api.UpdateNodeSizeResponse{
			Code:   roadmap_content_api.UpdateNodeSizeResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	//检查节点是否存在
	exist, err := roadmap_dao.NodeDao.Exist(ctx, req.RoadmapId, req.NodeId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &roadmap_content_api.UpdateNodeSizeResponse{
			Code:   roadmap_content_api.UpdateNodeSizeResponse_CODE_NO_NODE,
			ErrMsg: "节点不存在",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = roadmap_dao.NodeDao.UpdateSize(sessCtx, req.RoadmapId, req.NodeId, req.NodeSize.W, req.NodeSize.H)
		if err != nil {
			return nil, err
		}
		return &roadmap_content_api.UpdateNodeSizeResponse{
			Code: roadmap_content_api.UpdateNodeSizeResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*roadmap_content_api.UpdateNodeSizeResponse), nil
}

func (apiImpl *RoadmapContentApiImpl) UpdateNodePosition(ctx context.Context, req *roadmap_content_api.UpdateNodePositionRequest) (*roadmap_content_api.UpdateNodePositionResponse, error) {
	ownerType := roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_ADMIN
	ownerUserId := ""
	var roadmapPerm *admin_auth_api.RoadmapPerm
	isWhiteUser := false

	userSess, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if ok {
		ownerType = roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_USER
		ownerUserId = userSess.UserId
		exist, err := roadmap_dao.WhiteUserDao.Exist(ctx, userSess.UserId)
		if err != nil {
			return nil, err
		}
		isWhiteUser = exist
	} else {
		adminSess, ok := dao.CacheDao.GetAdminSession(ctx, req.SessionId)
		if !ok {
			return &roadmap_content_api.UpdateNodePositionResponse{
				Code:   roadmap_content_api.UpdateNodePositionResponse_CODE_WRONG_SESSION,
				ErrMsg: "会话不存在",
			}, nil
		}
		if !adminSess.AuthOk {
			return &roadmap_content_api.UpdateNodePositionResponse{
				Code:   roadmap_content_api.UpdateNodePositionResponse_CODE_NOT_AUTH,
				ErrMsg: "未授权会话",
			}, nil
		}
		adminUserCfg, err := admin_common.GetAdminUserConfig(ctx, apiImpl.adminCfg, adminSess.UserName)
		if err != nil {
			return nil, err
		}
		if !adminUserCfg.PermInfo.RoadmapPerm.Read {
			return &roadmap_content_api.UpdateNodePositionResponse{
				Code:   roadmap_content_api.UpdateNodePositionResponse_CODE_NO_PERMISSION,
				ErrMsg: "没有权限",
			}, nil
		}
		ownerType = roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_ADMIN
		ownerUserId = adminSess.UserName
		roadmapPerm = adminUserCfg.PermInfo.RoadmapPerm
	}

	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &roadmap_content_api.UpdateNodePositionResponse{
			Code:   roadmap_content_api.UpdateNodePositionResponse_CODE_NO_ROADMAP,
			ErrMsg: "路线图不存在",
		}, nil
	}
	userPerm := apiImpl.calcUserPerm(roadmapItem, ownerType, ownerUserId, roadmapPerm, isWhiteUser)
	if !userPerm.CanUpdateContent {
		return &roadmap_content_api.UpdateNodePositionResponse{
			Code:   roadmap_content_api.UpdateNodePositionResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	//检查节点是否存在
	exist, err := roadmap_dao.NodeDao.Exist(ctx, req.RoadmapId, req.NodeId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &roadmap_content_api.UpdateNodePositionResponse{
			Code:   roadmap_content_api.UpdateNodePositionResponse_CODE_NO_NODE,
			ErrMsg: "节点不存在",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = roadmap_dao.NodeDao.UpdatePosition(sessCtx, req.RoadmapId, req.NodeId, req.NodePosition.X, req.NodePosition.Y)
		if err != nil {
			return nil, err
		}
		return &roadmap_content_api.UpdateNodePositionResponse{
			Code: roadmap_content_api.UpdateNodePositionResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*roadmap_content_api.UpdateNodePositionResponse), nil
}

func (apiImpl *RoadmapContentApiImpl) UpdateNodeData(ctx context.Context, req *roadmap_content_api.UpdateNodeDataRequest) (*roadmap_content_api.UpdateNodeDataResponse, error) {
	ownerType := roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_ADMIN
	ownerUserId := ""
	var roadmapPerm *admin_auth_api.RoadmapPerm
	isWhiteUser := false

	userSess, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if ok {
		ownerType = roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_USER
		ownerUserId = userSess.UserId
		exist, err := roadmap_dao.WhiteUserDao.Exist(ctx, userSess.UserId)
		if err != nil {
			return nil, err
		}
		isWhiteUser = exist
	} else {
		adminSess, ok := dao.CacheDao.GetAdminSession(ctx, req.SessionId)
		if !ok {
			return &roadmap_content_api.UpdateNodeDataResponse{
				Code:   roadmap_content_api.UpdateNodeDataResponse_CODE_WRONG_SESSION,
				ErrMsg: "会话不存在",
			}, nil
		}
		if !adminSess.AuthOk {
			return &roadmap_content_api.UpdateNodeDataResponse{
				Code:   roadmap_content_api.UpdateNodeDataResponse_CODE_NOT_AUTH,
				ErrMsg: "未授权会话",
			}, nil
		}
		adminUserCfg, err := admin_common.GetAdminUserConfig(ctx, apiImpl.adminCfg, adminSess.UserName)
		if err != nil {
			return nil, err
		}
		if !adminUserCfg.PermInfo.RoadmapPerm.Read {
			return &roadmap_content_api.UpdateNodeDataResponse{
				Code:   roadmap_content_api.UpdateNodeDataResponse_CODE_NO_PERMISSION,
				ErrMsg: "没有权限",
			}, nil
		}
		ownerType = roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_ADMIN
		ownerUserId = adminSess.UserName
		roadmapPerm = adminUserCfg.PermInfo.RoadmapPerm
	}

	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &roadmap_content_api.UpdateNodeDataResponse{
			Code:   roadmap_content_api.UpdateNodeDataResponse_CODE_NO_ROADMAP,
			ErrMsg: "路线图不存在",
		}, nil
	}
	userPerm := apiImpl.calcUserPerm(roadmapItem, ownerType, ownerUserId, roadmapPerm, isWhiteUser)
	if !userPerm.CanUpdateContent {
		return &roadmap_content_api.UpdateNodeDataResponse{
			Code:   roadmap_content_api.UpdateNodeDataResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	//检查节点是否存在
	nodeItem, err := roadmap_dao.NodeDao.Get(ctx, req.RoadmapId, req.NodeId)
	if err != nil {
		return &roadmap_content_api.UpdateNodeDataResponse{
			Code:   roadmap_content_api.UpdateNodeDataResponse_CODE_NO_NODE,
			ErrMsg: "节点不存在",
		}, nil
	}
	dataOk := false
	if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_LABEL) {
		_, dataOk = req.NodeData.(*roadmap_content_api.UpdateNodeDataRequest_TextData)
	} else if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_RICH_TEXT) {
		_, dataOk = req.NodeData.(*roadmap_content_api.UpdateNodeDataRequest_RichTextData)
	} else if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_TOPIC) || nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_SUB_TOPIC) {
		_, dataOk = req.NodeData.(*roadmap_content_api.UpdateNodeDataRequest_TopicData)
	} else if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_TODO_LIST) {
		_, dataOk = req.NodeData.(*roadmap_content_api.UpdateNodeDataRequest_TodoListData)
	} else if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_GROUP) {
		_, dataOk = req.NodeData.(*roadmap_content_api.UpdateNodeDataRequest_GroupData)
	} else if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_ROADMAP_REF) {
		_, dataOk = req.NodeData.(*roadmap_content_api.UpdateNodeDataRequest_RoadmapRefData)
	} else if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_WEB_LINK) {
		_, dataOk = req.NodeData.(*roadmap_content_api.UpdateNodeDataRequest_WebLinkData)
	} else if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_CODE) {
		_, dataOk = req.NodeData.(*roadmap_content_api.UpdateNodeDataRequest_CodeData)
	}
	if !dataOk {
		return &roadmap_content_api.UpdateNodeDataResponse{
			Code:   roadmap_content_api.UpdateNodeDataResponse_CODE_WRONG_DATA,
			ErrMsg: "错误的数据",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_LABEL) {
			nodeData := req.NodeData.(*roadmap_content_api.UpdateNodeDataRequest_TextData)
			err = roadmap_dao.NodeDao.UpdateTextData(sessCtx, req.RoadmapId, req.NodeId, &roadmap_dao.NodeDataTextDbItem{
				FontSize:   nodeData.TextData.FontSize,
				FontWeight: nodeData.TextData.FontWeight,
				FontColor:  nodeData.TextData.FontColor,
				Content:    nodeData.TextData.Content,
				BgColor:    nodeData.TextData.BgColor,
			})
			if err != nil {
				return nil, err
			}
		} else if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_RICH_TEXT) {
			nodeData := req.NodeData.(*roadmap_content_api.UpdateNodeDataRequest_RichTextData)
			err = roadmap_dao.NodeDao.UpdateRichTextData(sessCtx, req.RoadmapId, req.NodeId, &roadmap_dao.NodeDataRichTextDbItem{
				Content: nodeData.RichTextData.Content,
				BgColor: nodeData.RichTextData.BgColor,
			})
			if err != nil {
				return nil, err
			}
		} else if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_TOPIC) || nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_SUB_TOPIC) {
			nodeData := req.NodeData.(*roadmap_content_api.UpdateNodeDataRequest_TopicData)
			linkList := []roadmap_dao.ExtraLinkItemDbItem{}
			if nodeData.TopicData.LinkList != nil {
				for _, linkItem := range nodeData.TopicData.LinkList {
					linkList = append(linkList, roadmap_dao.ExtraLinkItemDbItem{
						LinkId:    linkItem.LinkId,
						LinkType:  uint32(linkItem.LinkType),
						LinkTitle: linkItem.LinkTitle,
						LinkUrl:   linkItem.LinkUrl,
					})
				}
			}
			err = roadmap_dao.NodeDao.UpdateTopicData(sessCtx, req.RoadmapId, req.NodeId, &roadmap_dao.NodeDataTopicDbItem{
				FontSize:    nodeData.TopicData.FontSize,
				FontWeight:  nodeData.TopicData.FontWeight,
				FontColor:   nodeData.TopicData.FontColor,
				Title:       nodeData.TopicData.Title,
				BgColor:     nodeData.TopicData.BgColor,
				Content:     nodeData.TopicData.Content,
				LearnPolicy: uint32(nodeData.TopicData.LearnPolicy),
				LinkList:    linkList,
			})
			if err != nil {
				return nil, err
			}
		} else if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_TODO_LIST) {
			nodeData := req.NodeData.(*roadmap_content_api.UpdateNodeDataRequest_TodoListData)
			itemList := []roadmap_dao.NodeTodoItemDbItem{}
			for _, srcItem := range nodeData.TodoListData.ItemList {
				itemList = append(itemList, roadmap_dao.NodeTodoItemDbItem{
					TodoId: srcItem.TodoId,
					Title:  srcItem.Title,
				})
			}
			err = roadmap_dao.NodeDao.UpdateTodoListData(sessCtx, req.RoadmapId, req.NodeId, &roadmap_dao.NodeDataTodoListDbItem{
				ItemList: itemList,
				BgColor:  nodeData.TodoListData.BgColor,
			})
			if err != nil {
				return nil, err
			}
		} else if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_GROUP) {
			nodeData := req.NodeData.(*roadmap_content_api.UpdateNodeDataRequest_GroupData)
			err = roadmap_dao.NodeDao.UpdateGroupData(sessCtx, req.RoadmapId, req.NodeId, &roadmap_dao.NodeDataGroupDbItem{
				BgColor:      nodeData.GroupData.BgColor,
				BorderColor:  nodeData.GroupData.BorderColor,
				BorderRadius: nodeData.GroupData.BorderRadius,
			})
			if err != nil {
				return nil, err
			}
		} else if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_ROADMAP_REF) {
			nodeData := req.NodeData.(*roadmap_content_api.UpdateNodeDataRequest_RoadmapRefData)
			err = roadmap_dao.NodeDao.UpdateRoadmapRefData(sessCtx, req.RoadmapId, req.NodeId, &roadmap_dao.NodeDataRoadmapRefDbItem{
				TargetTitle: nodeData.RoadmapRefData.TargetTitle,
				TargetId:    nodeData.RoadmapRefData.TargetId,
			})
			if err != nil {
				return nil, err
			}
		} else if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_WEB_LINK) {
			nodeData := req.NodeData.(*roadmap_content_api.UpdateNodeDataRequest_WebLinkData)
			err = roadmap_dao.NodeDao.UpdateWebLinkData(sessCtx, req.RoadmapId, req.NodeId, &roadmap_dao.NodeDataWebLinkDbItem{
				LinkName: nodeData.WebLinkData.LinkName,
				LinkUrl:  nodeData.WebLinkData.LinkUrl,
			})
			if err != nil {
				return nil, err
			}
		} else if nodeItem.BasicInfo.NodeType == uint32(roadmap_content_api.NODE_TYPE_NODE_CODE) {
			nodeData := req.NodeData.(*roadmap_content_api.UpdateNodeDataRequest_CodeData)
			err = roadmap_dao.NodeDao.UpdateCodeData(sessCtx, req.RoadmapId, req.NodeId, &roadmap_dao.NodeDataCodeDbItem{
				Lang: nodeData.CodeData.Lang,
				Code: nodeData.CodeData.Code,
			})
			if err != nil {
				return nil, err
			}
		}
		return &roadmap_content_api.UpdateNodeDataResponse{
			Code: roadmap_content_api.UpdateNodeDataResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*roadmap_content_api.UpdateNodeDataResponse), nil
}

func (apiImpl *RoadmapContentApiImpl) RemoveNode(ctx context.Context, req *roadmap_content_api.RemoveNodeRequest) (*roadmap_content_api.RemoveNodeResponse, error) {
	ownerType := roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_ADMIN
	ownerUserId := ""
	var roadmapPerm *admin_auth_api.RoadmapPerm
	isWhiteUser := false

	userSess, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if ok {
		ownerType = roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_USER
		ownerUserId = userSess.UserId
		exist, err := roadmap_dao.WhiteUserDao.Exist(ctx, userSess.UserId)
		if err != nil {
			return nil, err
		}
		isWhiteUser = exist
	} else {
		adminSess, ok := dao.CacheDao.GetAdminSession(ctx, req.SessionId)
		if !ok {
			return &roadmap_content_api.RemoveNodeResponse{
				Code:   roadmap_content_api.RemoveNodeResponse_CODE_WRONG_SESSION,
				ErrMsg: "会话不存在",
			}, nil
		}
		if !adminSess.AuthOk {
			return &roadmap_content_api.RemoveNodeResponse{
				Code:   roadmap_content_api.RemoveNodeResponse_CODE_NOT_AUTH,
				ErrMsg: "未授权会话",
			}, nil
		}
		adminUserCfg, err := admin_common.GetAdminUserConfig(ctx, apiImpl.adminCfg, adminSess.UserName)
		if err != nil {
			return nil, err
		}
		if !adminUserCfg.PermInfo.RoadmapPerm.Read {
			return &roadmap_content_api.RemoveNodeResponse{
				Code:   roadmap_content_api.RemoveNodeResponse_CODE_NO_PERMISSION,
				ErrMsg: "没有权限",
			}, nil
		}
		ownerType = roadmap_api.ROADMAP_OWNER_TYPE_ROADMAP_OWNER_ADMIN
		ownerUserId = adminSess.UserName
		roadmapPerm = adminUserCfg.PermInfo.RoadmapPerm
	}

	roadmapItem, err := roadmap_dao.RoadmapInfoDao.Get(ctx, req.RoadmapId)
	if err != nil {
		return &roadmap_content_api.RemoveNodeResponse{
			Code:   roadmap_content_api.RemoveNodeResponse_CODE_NO_ROADMAP,
			ErrMsg: "路线图不存在",
		}, nil
	}
	userPerm := apiImpl.calcUserPerm(roadmapItem, ownerType, ownerUserId, roadmapPerm, isWhiteUser)
	if !userPerm.CanUpdateContent {
		return &roadmap_content_api.RemoveNodeResponse{
			Code:   roadmap_content_api.RemoveNodeResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	//检查节点是否存在
	exist, err := roadmap_dao.NodeDao.Exist(ctx, req.RoadmapId, req.NodeId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &roadmap_content_api.RemoveNodeResponse{
			Code: roadmap_content_api.RemoveNodeResponse_CODE_OK,
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = roadmap_dao.NodeDao.Remove(sessCtx, req.RoadmapId, req.NodeId)
		if err != nil {
			return nil, err
		}
		err = roadmap_dao.EdgeDao.RemoveByFromNode(sessCtx, req.RoadmapId, req.NodeId)
		if err != nil {
			return nil, err
		}
		err = roadmap_dao.EdgeDao.RemoveByToNode(sessCtx, req.RoadmapId, req.NodeId)
		if err != nil {
			return nil, err
		}
		//清除用户状态
		err = roadmap_dao.StateDao.RemoveByNode(sessCtx, req.RoadmapId, req.NodeId)
		if err != nil {
			return nil, err
		}

		return &roadmap_content_api.RemoveNodeResponse{
			Code: roadmap_content_api.RemoveNodeResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*roadmap_content_api.RemoveNodeResponse), nil
}
